/**********************************************************************
* thcp_trdp_udp_demo.c
*
* THCP host demo source file for UDP interface
* THCP上位机UDP接口示例文件
*
***********************************************************************
*
* http://www.yacer.cn
* Copyright(C), Nanjing Yacer Technology Co.,Ltd. All rights reserved.
*
***********************************************************************
* 2024-12-18   created for demo
*
**********************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#ifndef __packed
#if defined(__GNUC__)
#define __packed __attribute__((packed))
#elif defined(_MSC_VER)
#define __packed
#else
#define __packed
#endif
#endif

#include "thcp_Inc.h"

// 需要在头文件thcp_Inc.h中声明/定义相关结构体和宏
// 例如：TMSG_CFG_BEGIN, TMSG_CFG_TRDP_INTF, TMSG_CFG_TRDP_SUB, TMSG_CFG_TRDP_PUB, TMSG_CFG_END
// 以及TID_CFG_BEGIN, TID_CFG_TRDP_INTF, TID_CFG_TRDP_SUB, TID_CFG_TRDP_PUB, TID_CFG_END等
// 还需要声明TMSG_TRDP_PD_PUB_HEADER, TMSG_TRDP_PD_PUB_BUFFER, TMSG_TRDP_PD_SUB_BUFFER等结构体
// 并确保所有结构体成员类型和顺序与协议一致

// Function prototype for udp_send_packet
int udp_send_packet(const char *ip, uint16_t port, const void *data, size_t data_len);

extern void thcp_send_dev_cfg(void);

/************************************************************************
* Global variables 全局变量
*/

// 配置消息个数
static uint16_t msgNum = 0;

// 配置消息结构体
static TMSG_CFG_BEGIN      beginMsg;
static TMSG_CFG_TRDP_INTF  trdpIntfMsg;
static TMSG_CFG_TRDP_SUB   trdpSubMsg;
static TMSG_CFG_TRDP_PUB   trdpPubMsg;
static TMSG_CFG_END        endMsg;

// 发送PD时的THCP数据缓存
static uint8_t thcpDataBuf[1500];

/************************************************************************
* DEFINES 定义
*/

// 接口配置参数
#define THCP_TRDP1_NETIFID             1
#define THCP_TRDP2_NETIFID             2
#define THCP_TRDP1_IPADDRESS           0x0A000164
#define THCP_TRDP2_IPADDRESS           0x0A000264
#define THCP_TRDP1_MASK                0xFFFFFF00
#define THCP_TRDP2_MASK                0xFFFFFF00
#define THCP_TRDP1_GATEWAY             0x0A000101
#define THCP_TRDP2_GATEWAY             0x0A000201

// PD订阅配置参数
#define THCP_TRDP1_SUB_COMID           1800
#define THCP_TRDP2_SUB_COMID           2800
#define THCP_TRDP1_SUB_MULTIADDR       0xEFFF0114
#define THCP_TRDP2_SUB_MULTIADDR       0xEFFF0214

// PD发布配置参数
#define THCP_TRDP1_PUB_COMID           1500
#define THCP_TRDP2_PUB_COMID           2500
#define THCP_TRDP1_PUB_INTERVAL        500000
#define THCP_TRDP2_PUB_INTERVAL        500000
#define THCP_TRDP1_PUB_DSTIPADD        0xEFFF010A
#define THCP_TRDP2_PUB_DSTIPADD        0xEFFF020A

/************************************************************************
*  FUNCTIONS 函数
*/

/************************************************************************
* 定时器超时
*/
static void thcp_timer_timeout(void)
{
    // 2秒内未收到TMSG_DEVICE_STARTUP，重新发送配置
    thcp_send_dev_cfg();
}

/************************************************************************
* 启动定时器
*/
static void thcp_timer_start(void)
{
    // TODO: 启动2秒定时器，超时回调thcp_timer_timeout
    // 需要结合实际平台定时器API实现
}

/************************************************************************
* 停止定时器
*/
static void thcp_timer_stop(void)
{
    // TODO: 停止2秒定时器
    // 需要结合实际平台定时器API实现
}

/************************************************************************
* 通过UDP发送数据给Device
*
* @pData      数据
* @dataLen    数据长度
*
* @return
*       0  : 没有错误
*       -1 : 错误
*/
static int thcp_udp_send(uint8_t *pData, int dataLen)
{
    // TODO: 实际应用中应从配置获取目标IP和端口
    // 这里写死为192.168.0.200:8000
    return udp_send_packet("192.168.0.200", 8000, pData, dataLen);
}

/************************************************************************
* 发送配置到Device
*/
void thcp_send_dev_cfg(void)
{
    msgNum = 0;

    // begin
    memset(&beginMsg, 0, sizeof(beginMsg));
    msgNum++;
    beginMsg.TID = TID_CFG_BEGIN;
    thcp_udp_send((uint8_t *)&beginMsg, sizeof(beginMsg));

    // TRDP netif 1
    memset(&trdpIntfMsg, 0, sizeof(trdpIntfMsg));
    msgNum++;
    trdpIntfMsg.TID = TID_CFG_TRDP_INTF;
    trdpIntfMsg.netifId = THCP_TRDP1_NETIFID;
    trdpIntfMsg.ipAddress = htonl(THCP_TRDP1_IPADDRESS);
    trdpIntfMsg.netMask = htonl(THCP_TRDP1_MASK);
    trdpIntfMsg.gateway = htonl(THCP_TRDP1_GATEWAY);
    thcp_udp_send((uint8_t *)&trdpIntfMsg, sizeof(trdpIntfMsg));

    // TRDP netif 2
    memset(&trdpIntfMsg, 0, sizeof(trdpIntfMsg));
    msgNum++;
    trdpIntfMsg.TID = TID_CFG_TRDP_INTF;
    trdpIntfMsg.netifId = THCP_TRDP2_NETIFID;
    trdpIntfMsg.ipAddress = htonl(THCP_TRDP2_IPADDRESS);
    trdpIntfMsg.netMask = htonl(THCP_TRDP2_MASK);
    trdpIntfMsg.gateway = htonl(THCP_TRDP2_GATEWAY);
    thcp_udp_send((uint8_t *)&trdpIntfMsg, sizeof(trdpIntfMsg));

    // TRDP netif 1 subscribe
    memset(&trdpSubMsg, 0, sizeof(trdpSubMsg));
    msgNum++;
    trdpSubMsg.TID = TID_CFG_TRDP_SUB;
    trdpSubMsg.netifId = THCP_TRDP1_NETIFID;
    trdpSubMsg.comId = htonl(THCP_TRDP1_SUB_COMID);
    trdpSubMsg.multicastAddr = htonl(THCP_TRDP1_SUB_MULTIADDR);
    thcp_udp_send((uint8_t *)&trdpSubMsg, sizeof(trdpSubMsg));

    // TRDP netif 2 subscribe
    memset(&trdpSubMsg, 0, sizeof(trdpSubMsg));
    msgNum++;
    trdpSubMsg.TID = TID_CFG_TRDP_SUB;
    trdpSubMsg.netifId = THCP_TRDP2_NETIFID;
    trdpSubMsg.comId = htonl(THCP_TRDP2_SUB_COMID);
    trdpSubMsg.multicastAddr = htonl(THCP_TRDP2_SUB_MULTIADDR);
    thcp_udp_send((uint8_t *)&trdpSubMsg, sizeof(trdpSubMsg));

    // TRDP netif 1 publish
    memset(&trdpPubMsg, 0, sizeof(trdpPubMsg));
    msgNum++;
    trdpPubMsg.TID = TID_CFG_TRDP_PUB;
    trdpPubMsg.netifId = THCP_TRDP1_NETIFID;
    trdpPubMsg.comId = htonl(THCP_TRDP1_PUB_COMID);
    trdpPubMsg.cycleTime = htonl(THCP_TRDP1_PUB_INTERVAL);
    trdpPubMsg.dstIpAddress = htonl(THCP_TRDP1_PUB_DSTIPADD);
    thcp_udp_send((uint8_t *)&trdpPubMsg, sizeof(trdpPubMsg));

    // TRDP netif 2 publish
    memset(&trdpPubMsg, 0, sizeof(trdpPubMsg));
    msgNum++;
    trdpPubMsg.TID = TID_CFG_TRDP_PUB;
    trdpPubMsg.netifId = THCP_TRDP2_NETIFID;
    trdpPubMsg.comId = htonl(THCP_TRDP2_PUB_COMID);
    trdpPubMsg.cycleTime = htonl(THCP_TRDP2_PUB_INTERVAL);
    trdpPubMsg.dstIpAddress = htonl(THCP_TRDP2_PUB_DSTIPADD);
    thcp_udp_send((uint8_t *)&trdpPubMsg, sizeof(trdpPubMsg));

    // end
    memset(&endMsg, 0, sizeof(endMsg));
    msgNum++;
    endMsg.TID = TID_CFG_END;
    endMsg.cfgMsgNum = htons(msgNum);
    thcp_udp_send((uint8_t *)&endMsg, sizeof(endMsg));

    // 启动定时器监测startup消息
    thcp_timer_start();
}

/************************************************************************
* host调用这个函数发布PD数据
*
* @netifId      从哪个TRDP接口发送PD
* @comId        发送comId
* @pTrdpData    过程数据
* @trdpDataLen  过程数据长度
*
* @return
*       0  : 没有错误
*       -1 : 有错误
*/
int thcp_send_trdp_pub(uint8_t netifId, uint32_t comId, uint8_t *pTrdpData, uint16_t trdpDataLen)
{
    TMSG_TRDP_PD_PUB_BUFFER *pPubMsg;

    memset(thcpDataBuf, 0, sizeof(thcpDataBuf));

    // 检查长度
    if ((trdpDataLen + sizeof(TMSG_TRDP_PD_PUB_HEADER)) > sizeof(thcpDataBuf)) {
        return -1;
    }

    pPubMsg = (TMSG_TRDP_PD_PUB_BUFFER *)thcpDataBuf;
    memcpy((void *)(pPubMsg->userData), pTrdpData, trdpDataLen);
    pPubMsg->header.TID = TID_TRDP_PD_PUB;
    pPubMsg->header.netifId = netifId;
    pPubMsg->header.dataLength = htons(trdpDataLen);
    pPubMsg->header.comId = htonl(comId);

    // 发送消息
    if (0 != thcp_udp_send((uint8_t *)thcpDataBuf, (trdpDataLen + sizeof(TMSG_TRDP_PD_PUB_HEADER)))) {
        return -1;
    }

    return 0;
}

/************************************************************************
* 处理来自Device的TID_DEVICE_ONLINE消息
*/
static void thcp_proc_dev_online(TMSG_DEVICE_ONLINE *pMsg, int msgLen)
{
    // 可根据需要判断host是否ready
    thcp_send_dev_cfg();
}

/************************************************************************
* 根据thcp_result处理来自Device的TID_DEVICE_STARTUP消息
*/
static void thcp_proc_dev_startup(TMSG_DEVICE_STARTUP *pMsg, int msgLen)
{
    uint8_t thcp_result = pMsg->resultCode;

    thcp_timer_stop();

    if (THSTUP_SUCCESS == thcp_result) {
        return;
    }

    switch (thcp_result) {
        case THSTUP_BEGIN_LOST:
        case THSTUP_CFGMSG_NUM:
            thcp_send_dev_cfg();
            break;
        case THSTUP_LOCAL_CFG:
        case THSTUP_INVALID_HOST:
        case THSTUP_INVALID_CFG:
        case THSTUP_TRDP_SUBOV:
        case THSTUP_TRDP_PUBOV:
            // TODO: 配置错误，需根据错误码处理
            break;
        default:
            break;
    }
}

/************************************************************************
* 处理来自Device的PD订阅数据
*/
static void thcp_proc_dev_sub(TMSG_TRDP_PD_SUB_BUFFER *pMsg, int msgLen)
{
    uint16_t dataLen = ntohs(pMsg->header.dataLength);
    uint32_t comId = ntohl(pMsg->header.comId);

    // TODO: 处理订阅的过程数据
    // host_proc_sub_pd(comId, pMsg->userData, dataLen);
}

/************************************************************************
* 上位机调用这个函数分发来自Device的THCP消息
*/
void thcp_recv_process(uint8_t *pMsg, int msgLen)
{
    uint8_t TID = pMsg[0];

    switch (TID) {
        case TID_TRDP_PD_SUB:
            thcp_proc_dev_sub((TMSG_TRDP_PD_SUB_BUFFER *)pMsg, msgLen);
            break;
        case TID_DEVICE_ONLINE:
            thcp_proc_dev_online((TMSG_DEVICE_ONLINE *)pMsg, msgLen);
            break;
        case TID_DEVICE_STARTUP:
            thcp_proc_dev_startup((TMSG_DEVICE_STARTUP *)pMsg, msgLen);
            break;
        default:
            break;
    }
}

int main(void)
{
    // 注意：TMSG_MVB_PD_DATA_BUFFER结构体需在thcp_Inc.h中定义
    TMSG_MVB_PD_DATA_BUFFER pData;
    memset(&pData, 0, sizeof(pData));
    thcp_udp_send((uint8_t *)&pData, sizeof(pData));
    return 0;
}
